package top.licoba.configsdk;

import android.Manifest;
import android.app.Activity;
import android.content.Context;
import android.content.pm.PackageManager;
import android.os.Build;
import android.os.Handler;
import android.os.Message;
import androidx.core.content.ContextCompat;
import androidx.fragment.app.Fragment;

import com.inuker.bluetooth.library.BluetoothClient;
import com.inuker.bluetooth.library.Constants;
import com.inuker.bluetooth.library.connect.listener.BluetoothStateListener;
import com.inuker.bluetooth.library.connect.options.BleConnectOptions;
import com.inuker.bluetooth.library.connect.response.BleConnectResponse;
import com.inuker.bluetooth.library.connect.response.BleNotifyResponse;
import com.inuker.bluetooth.library.connect.response.BleWriteResponse;
import com.inuker.bluetooth.library.model.BleGattProfile;
import com.inuker.bluetooth.library.receiver.listener.BluetoothBondListener;
import com.inuker.bluetooth.library.search.SearchRequest;
import com.inuker.bluetooth.library.search.SearchResult;
import com.inuker.bluetooth.library.search.response.SearchResponse;

import java.util.UUID;

import static com.inuker.bluetooth.library.Code.REQUEST_SUCCESS;
import static top.licoba.configsdk.ConfigCode.ERROR_CONFIG_OVERTIME;
import static top.licoba.configsdk.ConfigCode.ERROR_DEVICE_NOT_FOUND;
import static top.licoba.configsdk.ConfigCode.STATE_CANCEL_SCAN;
import static top.licoba.configsdk.ConfigCode.STATE_CONNECTING;
import static top.licoba.configsdk.ConfigCode.STATE_CONNECTING_SERVER_FORWARD;
import static top.licoba.configsdk.ConfigCode.STATE_CONNECTING_SERVER_POST;
import static top.licoba.configsdk.ConfigCode.STATE_CONNECTING_WIFI;
import static top.licoba.configsdk.ConfigCode.STATE_CONNECT_FAILED;
import static top.licoba.configsdk.ConfigCode.STATE_CONNECT_SUCCESS;
import static top.licoba.configsdk.ConfigCode.STATE_MATCH_SUCCESS;
import static top.licoba.configsdk.ConfigCode.STATE_SCANNING;
import static top.licoba.configsdk.ConfigCode.STATE_START;
import static top.licoba.configsdk.ConfigCode.STATE_STOP_SCAN;
import static top.licoba.configsdk.ConfigCode.STATE_WRITE_DONE;
import static top.licoba.configsdk.ConfigCode.STATE_WRITING_DATA;
import static top.licoba.configsdk.MyConstant.CANT_FIND_DEVICE;
import static top.licoba.configsdk.MyConstant.CONFIG_OVERTIME;

/**
 * Created by licoba
 * Blog: https://www.licoba.top
 * Date: 2019/5/6  Time: 16:23
 * Remark: ConfigUtil.init(Activity or Fragment)
 */
public class ConfigUtil {
    public String wifiName = "CMCC-EDU";
    public String wifiPwd = "test123123";
    protected String macContainSting = "";//匹配规则
    protected int overTime = 40000;//配对超时时间


    private OnStateChangeListener mListener;
    private String mac;

    public void setOnStateChangeListener(OnStateChangeListener l) {
        mListener = l;
    }

    static Context mContext;
    private static ConfigUtil configUtil;
    private static Activity activityInstance;

    //取消蓝牙配置
    public void cancelConfig(){
        if (mClient!=null&&mac!=null){
            mClient.disconnect(mac);

        }
        mHandler.removeMessages(CANT_FIND_DEVICE);
        mHandler.removeMessages(CONFIG_OVERTIME);
    }

    public ConfigUtil macContainSting(String s) {
        configUtil.macContainSting = s;
        return configUtil;
    }


    public ConfigUtil overTime(int milliSecond ) {
        configUtil.overTime = milliSecond;
        return configUtil;
    }



    public ConfigUtil wifiName(String wifiName) {
        configUtil.wifiName = wifiName;
        return configUtil;
    }


    public ConfigUtil wifiPwd(String wifiPwd) {
        configUtil.wifiPwd = wifiPwd;
        return configUtil;
    }

    static BluetoothClient mClient;//全局单例，管理所有BLE设备的连接。


    public boolean checkLocationPermission() {
        if (Build.VERSION.SDK_INT >= 23) {
            //校验是否已具有模糊定位权限
            if (ContextCompat.checkSelfPermission(mContext,
                    Manifest.permission.ACCESS_COARSE_LOCATION)
                    != PackageManager.PERMISSION_GRANTED) {
                activityInstance.requestPermissions(
                        new String[]{Manifest.permission.ACCESS_COARSE_LOCATION}, 1);
            } else {
                return true;
            }
        } else {

            return true;
        }
        return false;
    }


    public static ConfigUtil init(Fragment fragment) {

        configUtil = new ConfigUtil();
        mContext = fragment.getContext();
        activityInstance = fragment.getActivity();
        mClient = new BluetoothClient(fragment.getActivity());

        return configUtil;
    }


    public static ConfigUtil init(Activity activity) {
        configUtil = new ConfigUtil();
        mContext = activity.getBaseContext();
        mClient = new BluetoothClient(activity);
        activityInstance = activity;
        return configUtil;
    }


    public ConfigUtil startBluConfig() {
        if (mClient.isBluetoothOpened()) {
            if (checkLocationPermission()) {
                startScan();
            }
        } else {//蓝牙未打开，申请开启蓝牙
            mClient.openBluetooth();
            mClient.registerBluetoothStateListener(mBluetoothStateListener);
        }

        return configUtil;
    }

    private Handler mHandler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            switch (msg.what) {
                case CANT_FIND_DEVICE:
                    if(mListener!=null)
                        mListener.onError(ERROR_DEVICE_NOT_FOUND);
                    break;
                case CONFIG_OVERTIME:
                    if(mListener!=null)
                        mListener.onError(ERROR_CONFIG_OVERTIME);
                    break;
                default:
                    break;
            }
        }
    };

    private void startScan() { //开始扫描附近的蓝牙设备
        SearchRequest request = new SearchRequest.Builder()
                .searchBluetoothLeDevice(3000, 3)   // 先扫BLE设备3次，每次3s
                .searchBluetoothClassicDevice(5000) // 再扫经典蓝牙5s
                .searchBluetoothLeDevice(2000)      // 再扫BLE设备2s
                .build();
        mHandler.sendEmptyMessageDelayed(CANT_FIND_DEVICE, 16000);//超时未发现设备

        mClient.search(request, new SearchResponse() {
            @Override
            public void onSearchStarted() {
                BluetoothLog.v("开始扫描蓝牙设备");
                if (mListener != null)
                    mListener.onConfig(STATE_START);
            }

            @Override
            public void onDeviceFounded(SearchResult device) {

                String name = device.getName();
                if (!name.equals("NULL")) {
                    if (mListener != null)
                        mListener.onConfig(STATE_SCANNING);
                    BluetoothLog.v("扫描到设备：" + device.getName());
                }

                if (name.contains(macContainSting)) {//name.equals(devicemac) ||
                    if (mListener != null)
                        mListener.onConfig(STATE_MATCH_SUCCESS);
                    BluetoothLog.v("蓝牙名称匹配成功：[" + name + "]");
                    mHandler.removeMessages(CANT_FIND_DEVICE);
                    mClient.stopSearch();
                    mac = device.getAddress();
                    connectBlue(mac);

                }
            }

            @Override
            public void onSearchStopped() {
                if (mListener != null)
                    mListener.onConfig(STATE_STOP_SCAN);
                BluetoothLog.v("停止扫描");
            }

            @Override
            public void onSearchCanceled() {
                if (mListener != null)
                    mListener.onConfig(STATE_CANCEL_SCAN);
                BluetoothLog.v("取消扫描");
            }
        });
    }


    //与设备蓝牙连接
    public void connectBlue(final String MAC) {
        if (mListener != null)
            mListener.onConfig(STATE_CONNECTING);
        BluetoothLog.v("与设备配对");

        BleConnectOptions options = new BleConnectOptions.Builder()
                .setConnectRetry(3)   // 连接如果失败重试3次
                .setConnectTimeout(30000)   // 连接超时30s
                .setServiceDiscoverRetry(3)  // 发现服务如果失败重试3次
                .setServiceDiscoverTimeout(20000)  // 发现服务超时20s
                .build();

        mClient.connect(MAC, options, new BleConnectResponse() {
            @Override
            public void onResponse(int code, BleGattProfile data) {
                // bondState = Constants.BOND_NONE, BOND_BONDING, BOND_BONDED
                if (code == REQUEST_SUCCESS) {
                    BluetoothLog.v("配对成功");
                    mHandler.sendEmptyMessageDelayed(CONFIG_OVERTIME, overTime);//超时配对失败
                    if (mListener != null)
                        mListener.onConfig(STATE_CONNECT_SUCCESS);
                    writeData(wifiName, wifiPwd, MAC);
                    openNotify(MAC);
                } else {
                    if (mListener != null)
                        mListener.onConfig(STATE_CONNECT_FAILED);
                    BluetoothLog.v("配对失败");

                    if (mClient!=null&&mac!=null){
                        mClient.disconnect(mac);
                    }
                    mHandler.removeMessages(CONFIG_OVERTIME);
                }
            }
        });
    }


    // 接受蓝牙设备发过来的消息
    // 这里有两个回调，onNotify是接收通知的。
    private void openNotify(String MAC) {
        BluetoothLog.v("打开Notify接收蓝牙消息");
        UUID openServiceUUID = UUID.fromString("6e400001-b5a3-f393-e0a9-e50e24dcca9e");
        UUID openCharacterUUID = UUID.fromString("6e400003-b5a3-f393-e0a9-e50e24dcca9e");

        mClient.notify(MAC, openServiceUUID, openCharacterUUID, new BleNotifyResponse() {
            @Override
            public void onNotify(UUID service, UUID character, byte[] value) {
                BluetoothLog.v("Notify...Received：" + MyUtil.ByteArrayToHex(value));
                ThreadPoolFactory.getNormalThread().executeTask(new parseBleData(value));
            }

            @Override
            public void onResponse(int code) {
                if (code == Constants.REQUEST_SUCCESS) {
                    BluetoothLog.v("Notify...onResponse");
                }
            }
        });
    }


    //解析蓝牙设备发送过来的数据
    private class parseBleData implements Runnable {
        private byte[] bytes;

        public parseBleData(byte[] value) {
            this.bytes = value;
        }

        @Override
        public void run() {
            if (bytes == null)
                return;
            if (bytes[3] == 0x30) {
                if (bytes[4] == 0x01) {
                    if (mListener != null)
                        mListener.onConfig(STATE_CONNECTING_WIFI);
                    BluetoothLog.v("设备连接WiFi中…");
                } else if (bytes[4] == 0x02) {
                    if (mListener != null)
                        mListener.onConfig(STATE_CONNECTING_SERVER_FORWARD);
                    BluetoothLog.v("连接前置服务器…");
                } else if (bytes[4] == 0x03) {
                    if (mListener != null)
                        mListener.onConfig(STATE_CONNECTING_SERVER_POST);
                    BluetoothLog.v("连接后置服务器…");
                } else if (bytes[4] == 0x04) {
                    if (mListener != null)
                        mListener.onSuccess();
                    BluetoothLog.v("配置成功！");
                    if (mClient!=null&&mac!=null){
                        mClient.disconnect(mac);
                    }
                    mHandler.removeMessages(CONFIG_OVERTIME);
                }
            }
        }
    }

    private byte[] sendData;

    /*往蓝牙设备写数据*/
    private void writeData(String wifiName, String wifiPwd, final String MAC) {
        final UUID writeCharacterUUID = UUID.fromString("6e400002-b5a3-f393-e0a9-e50e24dcca9e");
        final UUID writeServiceUUID = UUID.fromString("6e400001-b5a3-f393-e0a9-e50e24dcca9e");
        sendData = CommunicationDataUtils.getWifiDataByte(wifiName, wifiPwd);
        ThreadPoolFactory.getNormalThread().executeTask(new Runnable() {
            @Override
            public void run() {
                while (sendData.length > 20) {
                    //一次写入的byte[]不能超过20字节
                    byte[] bytes = MyUtil.subBytes(sendData, 0, 20);
                    mClient.write(MAC, writeServiceUUID, writeCharacterUUID, bytes, new BleWriteResponse() {
                        @Override
                        public void onResponse(int code) {
                            if (code == Constants.REQUEST_SUCCESS) {
                                if (mListener != null)
                                    mListener.onConfig(STATE_WRITING_DATA);
                                BluetoothLog.v("正在写入...");
                            }
                        }
                    });
                    sendData = MyUtil.subBytes(sendData, 20, sendData.length - 20);
                    try {
                        Thread.sleep(50);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }

                mClient.write(MAC, writeServiceUUID, writeCharacterUUID, sendData, new BleWriteResponse() {
                    @Override
                    public void onResponse(int code) {
                        if (code == Constants.REQUEST_SUCCESS) {
                            if (mListener != null)
                                mListener.onConfig(STATE_WRITE_DONE);
                            BluetoothLog.v("写入完毕");
                        }
                    }
                });


            }
        });
    }

    //监听设备配对状态变化
    private final BluetoothBondListener mBluetoothBondListener = new BluetoothBondListener() {
        @Override
        public void onBondStateChanged(String mac, int bondState) {
            // bondState = Constants.BOND_NONE, BOND_BONDING, BOND_BONDED
        }
    };


    //蓝牙打开或关闭需要一段时间，可以注册回调监听状态，回调的参数如果是true表示蓝牙已打开，false表示蓝牙关闭
    private final BluetoothStateListener mBluetoothStateListener = new BluetoothStateListener() {
        @Override
        public void onBluetoothStateChanged(boolean openOrClosed) {
            //蓝牙打开，开始扫描设备
            if (openOrClosed) {
                if (checkLocationPermission()) {
                    startScan();
                }
            } else {

            }
        }

    };


}
